package com.example.looktv

import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Bundle
import android.os.Handler
import android.os.IBinder
import android.os.Message
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.Toast
import android.widget.Toast.LENGTH_SHORT
import org.fourthline.cling.android.AndroidUpnpService
import org.fourthline.cling.android.AndroidUpnpServiceImpl
import org.fourthline.cling.android.FixedAndroidLogHandler
import org.fourthline.cling.controlpoint.ActionCallback
import org.fourthline.cling.model.action.ActionInvocation
import org.fourthline.cling.model.message.UpnpResponse
import org.fourthline.cling.model.meta.Device
import org.fourthline.cling.model.meta.LocalDevice
import org.fourthline.cling.model.meta.RemoteDevice
import org.fourthline.cling.model.meta.Service
import org.fourthline.cling.registry.DefaultRegistryListener
import org.fourthline.cling.registry.Registry
import org.fourthline.cling.registry.RegistryListener
import org.fourthline.cling.transport.Router
import org.fourthline.cling.transport.RouterException
import java.util.*
import java.util.logging.Level
import java.util.logging.Logger
import kotlin.concurrent.thread


class MainActivity : Activity() {


    private val registryListener = BrowseRegistryListener()

    private var upnpService: AndroidUpnpService? = null
    private var uris: List<TvSite>? = null
    private  var  device:Device<*,*,*>? = null
    private var tvloaded = false
    private var deviceConnected = false
    private var index = 0
    private var lineIndex= 0
    private var timer:Timer? = null
    private var channel = ""

    private var urimeta =
        "<DIDL-Lite xmlns=\"urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/\" xmlns:upnp=\"urn:schemas-upnp-org:metadata-1-0/upnp/\" xmlns:dc=\"http://purl.org/dc/elements/1.1/\" xmlns:sec=\"http://www.sec.co.kr/\"><item id=\"123\" parentID=\"-1\" restricted=\"1\"><upnp:storageMedium>UNKNOWN</upnp:storageMedium><upnp:writeStatus>UNKNOWN</upnp:writeStatus><dc:title>Video</dc:title><dc:creator>QGame</dc:creator><upnp:class>object.item.videoItem</upnp:class><res protocolInfo=\"http-get:*:video/*:DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000\">#uri</res></item></DIDL-Lite>"

    private val serviceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(className: ComponentName, service: IBinder) {
            upnpService = service as AndroidUpnpService


            // Get ready for future device advertisements
            upnpService!!.getRegistry().addListener(registryListener)

            // Now add all devices to the list we already know about
            for (device in upnpService!!.getRegistry().getDevices()) {
                registryListener.deviceAdded(device)
            }

            // Search asynchronously for all devices, they will respond soon
            upnpService!!.getControlPoint().search()
        }

        override fun onServiceDisconnected(className: ComponentName) {
            upnpService = null
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // Fix the logging integration between java.util.logging and Android internal logging
        org.seamless.util.logging.LoggingUtil.resetRootHandler(
            FixedAndroidLogHandler()
        )
        // Now you can enable logging as needed for various categories of Cling:
        // Logger.getLogger("org.fourthline.cling").setLevel(Level.FINEST);
        setContentView(R.layout.activity_main)
        // This will start the UPnP service if it wasn't already started
        applicationContext.bindService(
            Intent(this, AndroidUpnpServiceImpl::class.java),
            serviceConnection,
            Context.BIND_AUTO_CREATE
        )
        findViewById<Button>(R.id.change).setOnClickListener {
            startPlay(device,index,true)
        }
        findViewById<Button>(R.id.next).setOnClickListener {
            index = if(index >( uris!!.size - 1)) 0 else index+1
            startPlay(device, index)
        }
        findViewById<Button>(R.id.prev).setOnClickListener {
            index = if(index < 1 ) uris!!.size - 1 else index - 1
            startPlay(device, index)
        }
        thread(start = true) {
            uris = TvLoader.load(this)

            runOnUiThread(
                {
                    tvloaded = true
                    Log.d("TV","loaded")
                    startPlay(device, 0)
                }
            )
        }



    }
    override fun onDestroy() {
        super.onDestroy()
        upnpService?.getRegistry()?.removeListener(registryListener)
        // This will stop the UPnP service if nobody else is bound to it
        applicationContext.unbindService(serviceConnection)
    }
    // DOC:SERVICE_BINDING

    // DOC:SERVICE_BINDING
    // DOC:MENU
    override fun onCreateOptionsMenu(menu: Menu): Boolean {

        menu.add(0, 0, 0, R.string.searchLAN).setIcon(android.R.drawable.ic_menu_search)
        // DOC:OPTIONAL
        menu.add(0, 1, 0, R.string.switchRouter).setIcon(android.R.drawable.ic_menu_revert)
        menu.add(0, 2, 0, R.string.toggleDebugLogging)
            .setIcon(android.R.drawable.ic_menu_info_details)
        // DOC:OPTIONAL
        return true
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.getItemId()) {
            0 -> {
                if (upnpService == null) return false
                Toast.makeText(this, R.string.searchingLAN, Toast.LENGTH_SHORT).show()
                upnpService!!.getRegistry().removeAllRemoteDevices()
                upnpService!!.getControlPoint().search()
            }
            1 -> if (upnpService != null) {
                val router: Router = upnpService!!.get().getRouter()
                try {
                    if (router.isEnabled()) {
                        Toast.makeText(this, R.string.disablingRouter, Toast.LENGTH_SHORT).show()
                        router.disable()
                    } else {
                        Toast.makeText(this, R.string.enablingRouter, Toast.LENGTH_SHORT).show()
                        router.enable()
                    }
                } catch (ex: RouterException) {
                    Toast.makeText(
                        this,
                        getText(R.string.errorSwitchingRouter).toString() + ex.toString(),
                        Toast.LENGTH_LONG
                    ).show()
                    ex.printStackTrace(System.err)
                }
            }
            2 -> {
                val logger: Logger = Logger.getLogger("org.fourthline.cling")
                if (logger.getLevel() != null && !logger.getLevel().equals(Level.INFO)) {
                    Toast.makeText(this, R.string.disablingDebugLogging, Toast.LENGTH_SHORT).show()
                    logger.setLevel(Level.INFO)
                } else {
                    Toast.makeText(this, R.string.enablingDebugLogging, Toast.LENGTH_SHORT).show()
                    logger.setLevel(Level.FINEST)
                }
            }
        }
        return false
    }
      fun startPlay(
          device: Device<*, *, *>?,
          index: Int,
          changeline: Boolean = false
      ) {

          var fixedIndex = Math.min(index, uris?.size?.minus(1)!!)
          Toast.makeText(this,"开始播放${fixedIndex+1} 频道",LENGTH_SHORT).show()
          var tvuris = uris?.get(fixedIndex)?.uris
          if (!changeline){
              lineIndex = 0
          }else{
              lineIndex = if (lineIndex > tvuris!!.size-1) 0 else lineIndex+1
          }
          var uri = tvuris?.get(lineIndex)
          if (!tvloaded || !deviceConnected){
              return
          }
          findViewById<Button>(R.id.next).isEnabled =true
          if (device != null) {
              setAvTransport(device, uri!!, object : Handler.Callback {
                  override fun handleMessage(msg: Message): Boolean {
                      play(device)
                      this@MainActivity.index = fixedIndex
                      return true
                  }

              })
          }

    }

    private var playing = true
    private fun play(device: Device<*, *, *>) {
        if (playing){
            return
        }
        var playAction = device.services.map {
            it.getAction("Play")
        }.filterNotNull().first()
        var invocation = ActionInvocation(playAction)
        invocation.setInput("InstanceID", "0")
        invocation.setInput("Speed", "1.0")

        upnpService?.controlPoint?.execute(object : ActionCallback(invocation) {
            override fun failure(
                invocation: ActionInvocation<out Service<*, *>>?,
                operation: UpnpResponse?,
                defaultMsg: String?
            ) {
                Log.d("Upnp play", "fail")
            }

            override fun success(invocation: ActionInvocation<out Service<*, *>>?) {
                Log.d("Upnp play", "success")
                playing = true
            }

        })

    }

    private fun setAvTransport(device: Device<*, *, *>, uri: String, callback: Handler.Callback) {
        var setAVTransportURIActions = device.services.map {
            it.getAction("SetAVTransportURI")
        }.filterNotNull()
        if (setAVTransportURIActions.size == 0){
            return
        }

        var setAVTransportURIActionInvocation = ActionInvocation(setAVTransportURIActions.first());
        setAVTransportURIActionInvocation.setInput("InstanceID", "0")

        setAVTransportURIActionInvocation.setInput("CurrentURI", uri)
        setAVTransportURIActionInvocation.setInput(
            "CurrentURIMetaData",
            urimeta.replace("#uri", uri)
        )
        upnpService?.controlPoint?.execute(object :
            ActionCallback(setAVTransportURIActionInvocation) {
            override fun failure(
                invocation: ActionInvocation<out Service<*, *>>?,
                operation: UpnpResponse?,
                defaultMsg: String?
            ) {
                TODO("Not yet implemented")
            }

            override fun success(invocation: ActionInvocation<out Service<*, *>>?) {
                val msg = Message()
                callback.handleMessage(msg)
            }

        })


    }

    inner class BrowseRegistryListener : DefaultRegistryListener(), RegistryListener {
        /* Discovery performance optimization for very slow Android devices! */
        override fun remoteDeviceDiscoveryStarted(registry: Registry?, device: RemoteDevice) {
            deviceAdded(device)
        }


        override fun remoteDeviceDiscoveryFailed(
            registry: Registry?,
            device: RemoteDevice,
            ex: Exception?
        ) {
            runOnUiThread(Runnable {
                Log.d("Upnp", "Discovery failed of '" + device.getDisplayString().toString(), ex)
                Toast.makeText(
                    this@MainActivity,
                    "Discovery failed of '" + device.getDisplayString()
                        .toString() + "': " + (ex?.toString()
                        ?: "Couldn't retrieve device/service descriptors"),
                    Toast.LENGTH_LONG
                ).show()
            })
            deviceRemoved(device)
        }

        /* End of optimization, you can remove the whole block if your Android handset is fast (>= 600 Mhz) */
        override fun remoteDeviceAdded(registry: Registry?, device: RemoteDevice) {
            deviceAdded(device)
        }

        override fun remoteDeviceRemoved(registry: Registry?, device: RemoteDevice) {
            deviceRemoved(device)
        }

        override fun localDeviceAdded(registry: Registry?, device: LocalDevice) {
            deviceAdded(device)
        }

        override fun localDeviceRemoved(registry: Registry?, device: LocalDevice) {
            deviceRemoved(device)
        }

        fun deviceAdded(d: Device<*, *, *>) {
            val name: String =
                if (d.getDetails() != null && d.getDetails()
                        .getFriendlyName() != null
                ) d.getDetails().getFriendlyName() else d.getDisplayString()
            Log.d("Upnp","find "+ name)
            if(name.contains("电视果")!!){
                device = d
                deviceConnected = true
                Log.d("Upnp","loaded")
                runOnUiThread({
                    startPlay(device, 0)
                })

            }
        }

        fun deviceRemoved(device: Device<*, *, *>) {
         }
    }

    fun changeChannel(view: View) {
        val btn =  view as Button
        channel += btn.text
        timer?.cancel()
        timer = Timer()
        timer!!.schedule(object:TimerTask(){
            override fun run() {
                runOnUiThread({
                    startPlay(device,channel.toInt())
                    channel = ""
                })
            }

        },2000)
    }
}